﻿/*
ParallelPlatform Project - A web platform to distribute and share knowledge
Online Editor - An online tool to create and play animations
Copyright (C) 2011 Daniel Guerrero Martínez & Sergio Rodríguez Lumley

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package Classes{
	//import flash.display.MovieClip;
	public class Action/* extends MovieClip */{
		
		// Actions with examples
		/* -- Insert --
		  An object has been inserted in stage.
		  INSERT, "fullID", "object", x, y
		*/
		static public const INSERT:uint = 0;
		
		/* -- Remove --
		  An object has been removed from scene
		  REMOVE, "fullID"
		*/
		static public const REMOVE:uint = 1;
		
		/* -- Move --
		  An object has been moved in scene
		  MOVE, "fullID", x_init, y_init, x_end, y_end
		*/
		static public const MOVE:uint = 2;
		
		/* -- Scale --
		  An object has been scaled, the scale operation keeps the value
		  relative to original size, so if an object has been scaled only 
		  horizontally: x_old = 1; y_old = 1; x_new = 2; y_new = 1;
		  SCALE, "fullID", x_old, y_old, x_new, y_new
		*/
		static public const SCALE:uint = 3;
		
		/* -- Rotate --
		  An object has been rotated (in degrees)
		  ROTATE, "fullID", old_angle, new_angle
		*/
		static public const ROTATE:uint = 4;
		
		/* -- Change depth --
		  An object has changed its depth
		  CHANGE_DEPTH, "fullID", z_old, z_new
		*/
		static public const CHANGE_DEPTH:uint = 5;
		
		/* -- Change text --
		  An object has changed its text
		  CHANGE_TEXT, "fullID", "oldtext", "newtext"
		*/
		static public const CHANGE_TEXT:uint = 6;
		
		/* -- Undo remove --
		  An object has been unmarked as removed, this is a hack
		  to allow undo a redo these actions, this should NEVER end up
		  in an animation save file!
		  INVALIDATE_REMOVE, "fullID"
		*/
		static public const INVALIDATE_REMOVE:uint = 7;
		
		/* -- Blur --
		  An object has been blurred, the blur operation keeps the value
		  relative to zero, so if an object has been blurred only 
		  horizontally: blurx_old = 1; blury_old = 1; blurx_new = 2; blury_new = 1;
		  BLUR, "fullID", blurx_old, blury_old, blurx_new, blury_new
		*/
		static public const BLUR:uint = 8;
		
		/* -- Paint --
		  An object has been painted manually, paint operation keeps all
		  information as numbers, so the key point here is what these mean.
		  Note this operation can only be done once, so no track of how
		  the object was before must be kept. Now, pay attention to how
		  this is done:
		  PAINT, "fullID", Array[<colors> <lines>]
		  	- <colors>: <num_colors> [<color> <coloredlines>]
				+ <num_colors>: number of pair of color-nlines affected to be read
				+ <color>: color in HEX format (0xFFFFFF)
				+ <coloredlines>: number of lines affected by this color (the
					first "coloredlines" lines will have the first color)
			- <lines>: <total_lines> [<npoints>[<x><y>...] ]
				+ <total_lines>: total number of lines to read
				+ <npoints>: total number of points for each line
				+ <x>: x coordinate of a point centered in the shape
				+ <y>: y coordinate of a point centered in the shape
		*/
		static public const PAINT:uint = 9;
		
		/* -- Invalidate previous actions --
		  Several actions must be invalidated in order to keep the
		  shape clean. This kind of action should never end up in
		  an animation, it is for editor's logic purposes only. At
		  least one action index must be invalidated. Invalidated actions
		  must be stored in order to undo this action (if not, when this action is applied
		  and undone several times, it could lead to logical errors). It should
		  only invalidate move, change_text, scale, rotate and blur.
		  INVALIDATE_PREV_ACTIONS, "fullID", Array[act_type, act_index1, act_index2, ...]
		
		*/
		static public const INVALIDATE_PREV_ACTIONS:uint = 100;
		
		/* -- Invalid --
		  An object to which this action has referred to has been eliminated,
		  the action itself is no longer valid
		  INVALID+type = action invalidated
		*/
		static public const INVALID:uint = 1000;
		
		private var type:uint;
		private var ID:String;
		private var str:String; // Extra string, sometimes used
		private var str2:String; // Extra string, used for text editing
		private var rest:Vector.<Number>;
		
		/**
		  Constructor
		*/
		public function Action(typeA:uint, idA, ...args){
			var offset:uint = 0;
			var i:uint = 0;
			
			type = typeA;
			ID = idA;
			
			if(type == Action.INVALIDATE_PREV_ACTIONS || type == Action.PAINT){
				
				var array:Array = args[0];
				rest = new Vector.<Number>(array.length);
				for(i = 0; i < array.length; ++i){
					rest[i] = Number(array[i]);
				}
			}else{
				
				if(type == Action.INSERT || type == Action.CHANGE_TEXT){
					str = args[0];
					++offset;
					if(type == Action.CHANGE_TEXT){
						str2 = args[1];
						++offset;
					}
				}
				
				if(args.length - offset > 0){
					rest = new Vector.<Number>(args.length - offset);
					
					for(i = 0; i < rest.length; ++i){
						rest[i] = args[i+offset];
					}
				}
			}
		}
		
		public function getType():uint{
			return type;
		}
		
		public function getShapeID():String{
			return ID;
		}
		
		public function getString(pos:uint):String{
			if(pos == 0)
				return str;
			else
				return str2;
		}
		
		public function getNumber(pos:uint):Number{
			return rest[pos];
		}
		
		public function getNumberLength():uint{
			return rest.length;
		}
		
		/**
		  Invalidates this action, in a way that it can be undone, this is a safe
		  operation as it checks if it was already invalid
		*/
		public function invalidate():void{
			if(type < INVALID) type += 1000;
		}
		
		/**
		  Makes this action valid again. This is a safe operation as it checks
		  if it was valid already
		*/
		public function makeValid():void{
			if(type >= INVALID) type = type%1000;
		}
		
		/**
		  Gets if this action has been invalidated
		  @return Boolean with true if it has been, false otherwise
		*/
		public function isInvalidated():Boolean{
			if(type >= INVALID) return true;
			else return false;
		}
		
		/**
		  Gets a printable String of the Action
		  @return String in a printable format
		*/
		public function printString():String{
			var ret:String = translateToString(type)+", "+ID;
			if(str != null) ret += ", "+str;
			if(str2 != null) ret += ", "+str2;
			if(rest != null) ret += ", "+rest.toString();
			return ret;
		}
		
		static public function translateToCode(string:String):uint{
			var ret:uint = INVALID;
			if(string.search("insert") >= 0) ret = INSERT;
			else if(string.search("remove") >= 0) ret = REMOVE;
			else if(string.search("move") >= 0) ret = MOVE;
			else if(string.search("scale") >= 0) ret = SCALE;
			else if(string.search("rotate") >= 0) ret = ROTATE;
			else if(string.search("change_depth") >= 0) ret = CHANGE_DEPTH;
			else if(string.search("change_text") >= 0) ret = CHANGE_TEXT;
			else if(string.search("invalidate_remove") >= 0) ret = INVALIDATE_REMOVE;
			else if(string.search("blur") >= 0) ret = BLUR;
			else if(string.search("paint") >= 0) ret = PAINT;
			else if(string.search("invalidate_prev_actions") >= 0) ret = INVALIDATE_PREV_ACTIONS;
			
			return ret;
		}
		
		static public function translateToString(code:uint):String{
			var ret:String = "invalid";
			if(code == INSERT) ret = "insert";
			else if(code == REMOVE) ret = "remove";
			else if(code == MOVE) ret = "move";
			else if(code == SCALE) ret = "scale";
			else if(code == ROTATE) ret = "rotate";
			else if(code == CHANGE_DEPTH) ret = "change_depth";
			else if(code == CHANGE_TEXT) ret = "change_text";
			else if(code == INVALIDATE_REMOVE) ret = "invalidate_remove";
			else if(code == BLUR) ret = "blur";
			else if(code == PAINT) ret = "paint";
			else if(code == INVALIDATE_PREV_ACTIONS) ret = "invalidate_prev_actions";
			
			return ret;
		}
		
	}
}